/**
 * Created by XianTao on 2015/8/7
 * <p/>
 * Copyright (c) 2015-2015
 * Apache License
 * Version 2.0, January 2004
 * http://www.apache.org/licenses/
 */
package org.lego.wechat.base.msg;

import freemarker.cache.StringTemplateLoader;
import freemarker.core.InvalidReferenceException;
import freemarker.template.Configuration;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import org.lego.wechat.base.msg.out.*;

import java.io.StringWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * 输出消息解析器
 */
@SuppressWarnings("deprecation")
public class OutMsgXmlBuilder {
    private static String encoding = "utf-8";
    private static Configuration config = initFreeMarkerConfiguration();

    /**
     * 生成输出消息字符串
     *
     * @param outMsg 输入消息对象
     * @return 输出消息字符串
     */
    public static String build(OutMsg outMsg) {
        if (outMsg == null) {
            throw new IllegalArgumentException("参数OutMsg不能为null");
        }
        Map root = new HashMap();
        // 供 OutMsg 里的 TEMPLATE 使用
        root.put("__msg", outMsg);
        try {
            Template template = config.getTemplate(outMsg.getClass().getSimpleName(), encoding);
            StringWriter sw = new StringWriter();
            template.process(root, sw);
            return sw.toString();
        } catch (InvalidReferenceException e) {
            throw new RuntimeException("可能是" + outMsg.getClass().getSimpleName() + "对象中的某些属性未赋值，请仔细检查", e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static Configuration initFreeMarkerConfiguration() {
        Configuration config = new Configuration();
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        initStringTemplateLoader(stringTemplateLoader);
        config.setTemplateLoader(stringTemplateLoader);

        // 模板缓存更新时间，对于OutMsg xml 在类文件中的模板来说已有热加载保障了更新
        config.setTemplateUpdateDelay(999999);
        // Set an error handler that prints errors so they are readable with a HTML browser
        config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        // Use beans wrapper (recommended for most applications)
        config.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
        // Set the default charset of the template files
        config.setDefaultEncoding(encoding);
        // Set the charset of the output. This is actually just a hint, that
        //   templates may require for URL encoding and for generating META element
        //   that uses http-equiv="Content-type".
        config.setOutputEncoding(encoding);
        // et the default locale
        config.setLocale(Locale.getDefault());
        config.setLocalizedLookup(false);
        // 去掉int型输出时的逗号, 例如: 123,456
        config.setNumberFormat("#0.#####");
        config.setDateFormat("yyyy-MM-dd");
        config.setTimeFormat("HH:mm:ss");
        config.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");
        return config;
    }

    private static void initStringTemplateLoader(StringTemplateLoader loader) {
        // text  文本消息
        loader.putTemplate(OutTextMsg.class.getSimpleName(), OutTextMsg.TEMPLATE);
        // news  图文消息
        loader.putTemplate(OutNewsMsg.class.getSimpleName(), OutNewsMsg.TEMPLATE);
        // voice 语音消息
        loader.putTemplate(OutVoiceMsg.class.getSimpleName(), OutVoiceMsg.TEMPLATE);
        // video 视频消息
        loader.putTemplate(OutShortVideoMsg.class.getSimpleName(), OutShortVideoMsg.TEMPLATE);
        // location 位置消息
        loader.putTemplate(OutLocationMsg.class.getSimpleName(),OutLocationMsg.TEMPLATE);
        // music 音乐消息
        loader.putTemplate(OutMusicMsg.class.getSimpleName(),OutMusicMsg.TEMPLATE);
        // image 图片消息
        loader.putTemplate(OutImgMsg.class.getSimpleName(),OutImgMsg.TEMPLATE);
    }

    public static String getEncoding() {
        return encoding;
    }

    public static void setEncoding(String encoding) {
        OutMsgXmlBuilder.encoding = encoding;
    }
}
